#pragma once

#include <lcir/ADT/OwningRefVector.h>

#include <initializer_list>
#include <map>
#include <memory>
#include <sstream>
#include <string_view>
#include <type_traits>
#include <vector>
namespace lcir {
class OpInstance;
class Prototype;
class ProtoInstance;
class Dialect;
class Type;
class Lambda;
class Constant;
class ExprTempInstance;
// 直接把Context搞成单例算了。。。
// 反正也没遇到啥同时出现两个context的情况，其他情况在加别的contex类处理
class GlobalContext {
  GlobalContext() = default;

public:
  template <class DialectTy> DialectTy *getDialect() {
    static std::unique_ptr<DialectTy> ptr;
    [[unlikely]] if (!ptr)
      ptr = std::make_unique<DialectTy>();
    return ptr.get();
  }
  static GlobalContext *get() {
    static GlobalContext ctx;
    return &ctx;
  }
  template <class OpTy> OpInstance *getOpInstance() {
    static std::unique_ptr<OpInstance> ptr(nullptr);
    [[unlikely]] if (!ptr)
      ptr = std::make_unique<OpInstance>();
    return ptr.get();
  }

  template <class ProtoTy> ProtoInstance *getProtoInstance() {
    static std::unique_ptr<ProtoInstance> ptr(nullptr);
    [[unlikely]] if (!ptr) { ptr = std::make_unique<ProtoInstance>(); }
    return ptr.get();
  }

  /// TODO: 后序考虑提出来成concept
  /// 获得BasicType
  template <class TypeTy> TypeTy *getType() {
    static std::unique_ptr<TypeTy> ptr{nullptr};
    [[unlikely]] if (!ptr) { ptr = std::make_unique<TypeTy>(); }
    return ptr.get();
  }

  /// 获得ComplexType
  template <class TypeTy, class... Args> TypeTy *getType(Args *...args) {
    static std::map<std::string, std::unique_ptr<TypeTy>> typeTable;
    // 将地址转为string
    std::stringstream ss;
    (ss << ... << args);
    auto it = typeTable.find(ss.str());
    [[likely]] if (it != typeTable.end()) { return it->second.get(); }
    typeTable[ss.str()] = std::make_unique<TypeTy>(args...);
    return typeTable[ss.str()].get();
  }

  /// 获取VarComplexType
  template <class TypeTy, class... Args>
  TypeTy *getType(const std::vector<Type *> &list, Args *...args) {
    static std::map<std::string, std::unique_ptr<TypeTy>> typeTable;
    // 将地址转为string
    std::stringstream ss;
    for (auto *i : list)
      ss << i;
    (ss << ... << args);
    auto it = typeTable.find(ss.str());
    [[likely]] if (it != typeTable.end()) { return it->second.get(); }
    typeTable[ss.str()] = std::make_unique<TypeTy>(list, args...);
    return typeTable[ss.str()].get();
  }

  template <class TypeTy> Type *getComplexLooseType() {
    static std::unique_ptr<Type> ptr{nullptr};
    [[unlikely]] if (!ptr) {
      ptr = std::make_unique<Type>("", nullptr, nullptr);
    }
    return ptr.get();
  }
  template <class ExprTemp> ExprTempInstance *getExprTempInstance() {
    static std::unique_ptr<ExprTempInstance> ptr;
    [[unlikely]] if (!ptr)
      ptr = std::make_unique<ExprTempInstance>();
    return ptr.get();
  }
  /**
   * @brief 获得Lambda
   */
  Lambda *getLamda(const std::vector<Type *> &paramTypes, Type *resultType);
  
  /**
   * @brief 获得Const
   */
  Constant *getConst(std::unique_ptr<Prototype> proto);
};
} // namespace lcir